home *** CD-ROM | disk | FTP | other *** search
- /*-
- * $Date: 7/29/95 6:27p $
- * $Workfile: fulog.cpp $
- * $Archive: /FULog/fulog.cpp $
- *---------------------------------------------------------------------
- *
- * Module Name : fulog.cpp
- *
- * Description : Flight Unlimited Log File listing program.
- * In addition to a normal log listing this program
- * allows including/excluding specific entries and
- * gives statistics about the flight time in different
- * planes and from different airports. Also gives some
- * extended lesson statistics.
- *
- *
- * Classification : Public Domain
- *
- * Status : New
- *
- * Initial Author : Jesper Hansen
- *
- * Restrictions : None
- *
- * Compiler : Watcom C++ 10.0 / Microsoft Visual C++ 1.51
- *
- * Notes : This file contain all the code for the Log program.
- * Most class code is implemented directly in the class,
- * to make the classes more readable.
- * Comments are sparse, this is a quick hack.
- * Contains long lines, way beyond 80 positions !
- *
- *
- *
- * Change Activity:
- * $Log: /FULog/fulog.cpp $
- *
- * 1 7/29/95 6:27p Jeha
- * wrote it !
- *
- *
- *---------------------------------------------------------------------
- -*/
-
- #include <iostream.h>
- #include <fstream.h>
- #include <strstrea.h>
- #include <iomanip.h>
- #include <assert.h>
- #include <time.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #include <dos.h>
-
- #define PILOT_FILE "pilot000.log" // default log file
- #define PLANE_FILE "planes.ful" // file containing plane names
- #define AIRPORT_FILE "airports.ful" // file containing airport names
- #define LESSON_FILE "lessons.ful" // file containing lesson names
-
- #define MAX_NAME_ENTRIES 100 // max entries allowed in plane,
- // airport and lesson files
-
- #define MAX_LOG_ENTRIES 5000 // max entries allowed in the log
-
- #define NUM_DISPLAY_FIELDS 6 // number of fields in list display
- #define FIELDIDS "dpiatc" // field name id's
-
- #define DEAD_BEEF_END 0x0A34 // figure this one out yourself
-
-
-
- #pragma pack(1) // need to pack the structs
-
- //
- // The log entry structure
- //
- // ( For a more detailed explanation of the log
- // file format, please see the readme file )
- //
- typedef struct
- {
- char entrytype; // type of entry
- long nextsimilar; // index of next entry of the same type
- long prevsimilar; // index of previous entry of the same type
- long next; // index of next entry
- long prev; // index of previous entry
- long date; // flight date in UTC format
- long flighttime; // duration of this flight
- int plane; // the plane used
- char planeid[6]; // the plane designation
- char comment[128]; // comment
- long reserved; // dont know
- int airport; // the airport used
- int maneuvernumber; // maneuver/group number for certification/award
- int certoraward; // flag for cetification (0) or award (1)
- int certnumber; // some internal certification/award value
- char filler[83]; // ?
- } LogRecord;
-
-
-
- //////////////////////////////////////////////////////////////////////
- // Class : NameArray
- //
- // Description : Handles a variable list of names.
- // The list is loaded from a standard ASCII file
- // containing a name on each line.
- //
- //////////////////////////////////////////////////////////////////////
- class NameArray
- {
- int m_z; // entry count
- char **m_name; // entry pointer
- public:
- NameArray() { m_z=0; m_name = new char*[MAX_NAME_ENTRIES]; }
- ~NameArray() { while (m_z) delete [] m_name[--m_z]; delete [] m_name; }
- void Load(char *fn) { ifstream ins(fn);
- if (!ins)
- {
- cout << "Error: File '" << strupr(fn) << "' not found !" << endl;
- exit(1);
- }
- while (!ins.eof())
- {
- m_name[m_z] = new char[40];
- ins.get(m_name[m_z],40);
- ins.ignore();
- if (!ins.eof())
- m_z++;
- }
- }
- int NumEntries() { return m_z; }
- char *GetEntry(int index) { return m_name[index]; }
- void Show(int index) { cout << m_name[index]; }
- };
-
- //////////////////////////////////////////////////////////////////////
- // Class : FLTime
- //
- // Description : Supplies some routines for handling time.
- // Conversion between packed time and h,m,s value.
- //
- //////////////////////////////////////////////////////////////////////
- class FLTime
- {
- long m_h;
- long m_m;
- long m_s;
- long m_t;
- public:
- FLTime() { m_h = m_m = m_s = m_t = 0; }
- void TimeToHMS() { m_s = m_t; m_h = m_s/3600; m_s -= m_h*3600;
- m_m = m_s/60; m_s -= m_m*60;
- }
- void HMSToTime() { m_t = m_h*3600+m_m*60*m_s; }
- long GetH() { return m_h; }
- long GetM() { return m_m; }
- long GetS() { return m_s; }
- long GetT() { return m_t; }
- void SetHMS(long ph,long pm,long ps) { m_h = ph; m_m = pm; m_s = ps; }
- void SetT(long pt) { m_t = pt; }
- void ShowHMS() { cout << setw(2) << setfill('0') << m_h << ':';
- cout << setw(2) << m_m << ':' << setw(2) << m_s;
- }
- void ShowT(long pt) { m_t = pt; TimeToHMS(); ShowHMS(); }
- };
-
-
-
- //////////////////////////////////////////////////////////////////////
- // Class : LogEntry
- //
- // Description : Handles the loading of and interfaces to the Log
- // file data.
- // The list is loaded from a standard ASCII file
- // containing a name on each line.
- //
- //////////////////////////////////////////////////////////////////////
-
- //
- // overloaded operator for loading log entries
- //
- istream& operator >> (istream& s,LogRecord& r)
- {
- s.read((unsigned char *)&r,sizeof(LogRecord));
- return s;
- }
-
- class LogEntry
- {
- LogRecord** m_entry; // pointer to log record array
- LogRecord* m_current; // pointer to the current record
- int m_z; // number of records read
- int m_first; // pointer to first user record
- int* m_lessonscores; // pointer to lesson score record
- char* m_Name; // pilot name
- char* m_Sex; // pilot sex
- char* m_Height; // pilot height (why do they need this ?)
- char* m_Birthday; // try taking a lesson this day (or cristmas (or new years day))
- public:
- LogEntry() { m_z = m_first = 0;
- m_entry = new LogRecord* [MAX_LOG_ENTRIES];
- m_current = 0;
- }
- ~LogEntry() { while (m_z) delete [] m_entry[--m_z]; delete [] m_entry; }
- void SetPersonal(LogRecord *pentry) {
- m_Sex = ((char *)&pentry->next);
- m_Height = ((char *)&pentry->next)+40;
- m_Birthday = ((char *)&pentry->next)+80;
- }
- void Load(char *fn) { ifstream ins(fn,ios::in | ios::binary);
- if (!ins)
- {
- cout << "Error: File '" << strupr(fn) << "' not found !" << endl;
- exit(1);
- }
- m_Name = new char[40];
- ins.read(m_Name,40);
- ins.seekg(DEAD_BEEF_END);
- while (!ins.fail())
- {
- m_entry[m_z] = new LogRecord;
- ins >> *m_entry[m_z];
- if ( (unsigned char)m_entry[m_z]->entrytype < 0x80 && !m_first)
- m_first = m_z;
- if ((unsigned char)m_entry[m_z]->entrytype == 0x80)
- m_lessonscores = (int *) &m_entry[m_z]->next;
- if ((unsigned char)m_entry[m_z]->entrytype == 0x82)
- SetPersonal(m_entry[m_z]);
- m_z++;
- }
- }
- int NumEntries() { return m_z; }
- LogRecord* Rewind() { m_current = m_entry[m_first]; return m_current; }
- LogRecord* GetNext() { m_current = ((long) m_current->next != -1) ? m_entry[m_current->next] : NULL;
- return m_current;
- }
- LogRecord* GetEntry(int index) { return m_entry[index]; }
- char *GetName() { return m_Name; }
- char *GetSex() { return m_Sex; }
- char *GetHeight() { return m_Height; }
- char *GetBirthday() { return m_Birthday; }
- int GetLessonScore(int plesson) { return m_lessonscores[plesson]; }
- };
-
-
- //////////////////////////////////////////////////////////////////////
- // Class : FULog
- //
- // Description : Main work horse.
- // Goes through the log entries, handles the inclusion/
- // exclusion of specific entries.
- // Maintains timings for planes and airports.
- // Also contains most of the display routines.
- //
- //////////////////////////////////////////////////////////////////////
- class FULog
- { NameArray p,a,l;
- LogEntry le;
- FLTime f;
-
- int m_pausecount; // pause screen count
- int m_pause; // pause screen flag
- char* m_fieldids; // pointer to fiels Id's
- int m_skip[NUM_DISPLAY_FIELDS]; // skip field array
- char* m_include; // pointer to include strings
- char* m_exclude; // pointer to exclude strings
- char* m_type; // pointer to include types
- long m_listtime; // sum of flight time listed
- long m_totaltime; // total summed flight time
- long* m_planetime; // summed flight time on individual planes
- long* m_airporttime; // summed flight time for airports
-
- public:
- FULog() { m_fieldids = FIELDIDS;
- memset(&m_skip,0,sizeof(m_skip));
- m_include = m_exclude = 0;
- m_type = "0123456789";
- m_listtime = m_totaltime = 0;
- m_pause = 0;
- m_pausecount = 0;
- }
- void Load(char* fn) { p.Load(PLANE_FILE);
- a.Load(AIRPORT_FILE);
- l.Load(LESSON_FILE);
- le.Load(fn ? fn : PILOT_FILE );
- m_planetime = new long[p.NumEntries()];
- for (int i=0;i<p.NumEntries();i++)
- m_planetime[i] = 0;
- m_airporttime = new long[a.NumEntries()];
- for (i=0;i<a.NumEntries();i++)
- m_airporttime[i] = 0;
- }
- void SetSkip(char c) { m_skip[strchr(m_fieldids,c) - m_fieldids] = 1; }
- int SkipState(int i) { return m_skip[i]; }
- void SetInclude(char *pc) { m_include = pc; }
- void SetExclude(char *pc) { m_exclude = pc; }
- int IsIncluded(char *pc);
- int IsExcluded(char *pc);
- void SetType(char *pc) { m_type = pc; }
- void ShowPilot() { cout << "Name : " << le.GetName() << endl;
- cout << "Sex : " << le.GetSex() << endl;
- cout << "Height : " << le.GetHeight() << endl;
- cout << "Birthday : " << le.GetBirthday() << endl;
- cout << endl;
- }
- void List();
- void SetPauseMode(int pmode) { m_pause = pmode; }
- void SetPauseCount(int pc) { m_pausecount = pc; }
- void CheckPause() { if (m_pause)
- {
- if (!m_pausecount--)
- {
- cout << " -- More --";
- cin.ignore();
- cout << "\r";
- m_pausecount = 23;
- }
- }
- }
- void ShowTime() { cout << "Listed Flight Time ";
- f.ShowT(m_listtime);
- cout << endl;
- CheckPause();
- cout << "Total Flight Time ";
- f.ShowT(m_totaltime);
- cout << endl;
- CheckPause();
- }
-
- void ShowStats() { cout << endl;
- CheckPause();
- cout << "Plane Flight Times" << endl;
- CheckPause();
- for (int i=0;i<p.NumEntries();i++)
- {
- cout << setw(17) << setfill(' ') << p.GetEntry(i) << " ";
- f.ShowT(m_planetime[i]);
- cout << " " << m_planetime[i]*100/m_totaltime << '%';
- cout << endl;
- CheckPause();
- }
- cout << endl;
- CheckPause();
- cout << "Airport Flight Times" << endl;
- CheckPause();
- for (i=0;i<a.NumEntries();i++)
- {
- cout << setw(17) << setfill(' ') << a.GetEntry(i) << " ";
- f.ShowT(m_airporttime[i]);
- cout << " " << m_airporttime[i]*100/m_totaltime << '%';
- cout << endl;
- CheckPause();
- }
- cout << endl;
- CheckPause();
- cout << "Lesson Statistics" << endl;
- CheckPause();
- cout << setw(30) << setfill(' ') << "Lesson" << " " << "Score Status\n";
- CheckPause();
- int lesson_total = 0;
- int lesson_count = 0;
- int score;
- for (i=0;i<l.NumEntries();i++)
- {
- score = le.GetLessonScore(i);
- cout << setw(30) << l.GetEntry(i) << " ";
- cout << setw(2) << score/10 << '.' << score - (score/10*10) << " ";
- cout << ((score >= 80) ? "Completed" : ((score != 0) ? "Trained" : "Not Tried"));
- cout << endl;
- CheckPause();
- if (score >= 80)
- {
- lesson_total += score;
- lesson_count++;
- }
- }
- cout << "\nAverage Score on Completed Lessons = ";
- if (lesson_count)
- {
- score = lesson_total / lesson_count;
- cout << score/10 << '.' << score - (score/10*10);
- }
- else
- cout << "No Lessons Completed";
- cout << endl;
-
- }
- };
-
- //
- // check whether the supplied string contains include strings
- //
- int FULog::IsIncluded(char* pc)
- { char *q;
-
- if (!m_include)
- return 1;
-
- char *a = strdup(m_include);
- q = strtok(a,",\0");
- while (q)
- {
- if (strstr(pc,q))
- {
- free(a);
- return 1;
- }
- q = strtok(NULL,",\0");
- }
- free(a);
- return 0;
- }
-
- //
- // check whether the supplied string contains exclude strings
- //
- int FULog::IsExcluded(char* pc)
- { char *q;
-
- if (!m_exclude)
- return 0;
-
- char *a = strdup(m_exclude);
- q = strtok(a,",\0");
- while (q)
- {
- if (strstr(pc,q))
- {
- free(a);
- return 1;
- }
- q = strtok(NULL,",\0");
- }
- free(a);
- return 0;
- }
-
-
- //
- // Main list routine
- // generates a complete line for include/exclude checks
- // then display all non-skipped fields
- //
- void FULog::List()
- { LogRecord* lr;
- char temp[80],temp2[80],field[80],*q;
- struct tm* stime;
- int padding;
-
-
- lr = le.Rewind();
- while (lr)
- {
- if ((unsigned char)lr->entrytype < 0x80)
- {
- *temp = *temp2 = *field = padding = 0;
- ostrstream testline(temp,80,ios::app);
- ostrstream outline(temp2,80,ios::app);
-
- m_totaltime += lr->flighttime;
-
- m_planetime[lr->plane] += lr->flighttime;
- m_airporttime[lr->airport] += lr->flighttime;
-
- stime = localtime((/*unsigned*/ long *)&lr->date);
- sprintf(field,"%2d/%-2d ",stime->tm_mday,stime->tm_mon+1); // format fields
- testline << field;
- if (!SkipState(0))
- {
- outline << field;
- padding += strlen(field);
- }
- sprintf(field,"%-9s ",p.GetEntry(lr->plane));
- testline << field;
- if (!SkipState(1))
- {
- outline << field;
- padding += strlen(field);
- }
- sprintf(field,"%5s ",lr->planeid);
- testline << field;
- if (!SkipState(2))
- {
- outline << field;
- padding += strlen(field);
- }
- sprintf(field,"%-12s ",a.GetEntry(lr->airport));
- testline << field;
- if (!SkipState(3))
- {
- outline << field;
- padding += strlen(field);
- }
-
- outline << '\0'; // why do we need this ?
- testline << '\0';
-
- if (strchr(m_type,lr->entrytype+'0') &&
- IsIncluded(testline.str()) &&
- !IsExcluded(testline.str()) )
- {
- m_listtime += lr->flighttime;
-
- cout << outline.str();
-
- if (!SkipState(4))
- {
- f.SetT(lr->flighttime);
- f.TimeToHMS();
- sprintf(field,"%02lu:%02lu:%02lu ",f.GetH(),f.GetM(),f.GetS());
- cout << field;
- padding += strlen(field);
- }
-
- if (!SkipState(5))
- {
- unsigned int len = 32;
- q = lr->comment;
- while (strlen(q) > len)
- {
- q += len;
- while (*q != ' ')
- q--;
- *q++ = '\n';
- }
-
- q = strtok(lr->comment,"\n\0"); // first part of string
- while (q) // while more
- {
- cout << q; // print it
-
- q = strtok(NULL,"\n\0"); // get next part
- if (q) // if more to come
- {
- cout << endl;
- CheckPause();
- cout << setfill(' ') << setw(padding) << ""; // pad with spaces
- }
- }
- }
- cout << endl;
- CheckPause();
- }
-
- }
- lr = le.GetNext();
- }
-
- cout << endl;
- CheckPause();
- }
-
-
- //////////////////////////////////////////////////////////////////////
- // Function : help
- //
- // Description : Display usage notes for the program
- //
- //////////////////////////////////////////////////////////////////////
- void help()
- {
- cout << "usage :\n";
- cout << " fulog [-options] [filename] [-options] \n\n";
- cout << "options can be placed either before or after the filename, and can\n";
- cout << "be prefixed with either '-' or '/'.\n";
- cout << "filename are the name of a Flight Unlimited pilot log file.\n";
- cout << "If no filename are specified, 'PILOT000.LOG' will be used as default.\n";
- cout << "Options :\n";
- cout << " -i<string>[,string] ... - include only fields containing the\n";
- cout << " given strings.\n";
- cout << " -e<string>[,string] ... - exclude fields containing the given strings.\n";
- cout << " -s[dpiatc] - skip the fields indicated.\n";
- cout << " (d=date,p=plane e.t.c.)\n";
- cout << " -t<n> - include only entries of the given type.\n";
- cout << " Types are : \n";
- cout << " 1 - Lessons\n";
- cout << " 2 - Solo Flight\n";
- cout << " 3 - Hoops Courses\n";
- cout << " 4 - Certification\n";
- cout << " -d - display extended statistics.\n";
- cout << " -p - pause on each screen.\n";
- cout << " -f - skip delay at program start.\n";
- cout << " -? or -h - display this help.";
- cout << endl;
- exit(0); // terminate
- }
-
- //////////////////////////////////////////////////////////////////////
- // Function : main
- //
- // Description : Well, main entry point actually
- //
- //////////////////////////////////////////////////////////////////////
-
- void main(int argc, char **argv)
- { char *fields[NUM_DISPLAY_FIELDS] = {"Date ","Plane ","Ident","Airport ","Time ","Comment "};
- int i,fastmode = 0,helpmode = 0, stats = 0, pause = 0;
- char c, *filename = NULL;
- FULog Log;
-
- //
- // parse argument list
- //
- for (i=1;i<argc;i++)
- {
- if (strcspn(argv[i],"-/"))
- filename = argv[i];
- else
- {
- switch ( c = *(++argv[i]) )
- {
- case 's' : // skip
- while ((c = *(++argv[i])) != 0)
- Log.SetSkip( c );
- break;
- case 'e' : // exclude
- Log.SetExclude( argv[i]+1 );
- break;
- case 'i' : // include
- Log.SetInclude( argv[i]+1 );
- break;
- case 't' : // type
- Log.SetType( argv[i]+1 );
- break;
- case 'd' :
- stats = 1;
- if (*(argv[i]+1) == '-')
- Log.SetInclude("dummy");
- break;
- case 'p' :
- pause = 1;
- break;
- case 'f' :
- fastmode = 1;
- break;
- case '?' :
- case 'h' :
- helpmode = 1;
- break;
- }
- }
- }
-
- //
- // display program header
- //
-
- cout << "\n\nFlight Unlimited Pilot Log, Luxury Edition :)\n";
- cout << "-----------------------------------------------\n";
- cout << "Jesper Hansen CIS:100335,3165 jeha@hk.enator.se\n";
- cout << "Version F1;4S July 1995 Public Domain\n";
- cout << "-----------------------------------------------\n\n";
-
- //
- // make sure the user sees it
- //
-
- // if (!fastmode) sleep(2);
-
- //
- // display help for the novice
- //
- if (helpmode) help();
-
- //
- // load files
- //
- Log.Load(filename);
-
- //
- // show pilot information
- //
- Log.ShowPilot();
-
- //
- // show fields names and underline each
- //
- for (i=0;i<NUM_DISPLAY_FIELDS;i++)
- if (!Log.SkipState(i))
- cout << fields[i] << " ";
- cout << endl;
- for (i=0;i<NUM_DISPLAY_FIELDS;i++)
- if (!Log.SkipState(i))
- cout << setw(strlen(fields[i])) << setfill('-') << "" << " ";
- cout << endl;
-
- //
- // set up pause mode
- //
- Log.SetPauseMode(pause);
- Log.SetPauseCount(8);
-
- //
- // list it
- //
- Log.List();
-
- //
- // display time statistics
- //
- Log.ShowTime();
-
- //
- // display extended statistics
- //
- if (stats) Log.ShowStats();
-
- // bye
- }
-